package org.artifact.core.plugin.dispatcher;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;

import org.artifact.core.constant.ArtifactErrorCode;
import org.artifact.core.context.packet.IPacket;
import org.artifact.core.context.packet.IPacketInterceptor;
import org.artifact.core.context.session.ISession;
import org.artifact.core.db.BaseDao;
import org.artifact.core.exception.AbstractArtifactException;
import org.artifact.core.exception.ArtifactExceptionUtil;
import org.artifact.core.lang.IModule;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.artifact.core.lang.IPlugin;

public class DispatcherPlugin implements IPlugin {
	
	static final Log log = LogFactory.get(DispatcherPlugin.class);

	/** 扫描器 */
	private Callable<Map<Integer,IModule>> scanner;

	/** 模块集 */
	private Map<Integer,IModule> modules;

	/** 拦截器 */
	private IPacketInterceptor interceptor;
	
	public DispatcherPlugin(Callable<Map<Integer,IModule>> scanner, IPacketInterceptor interceptor) {
		super();
		this.scanner = scanner;
		this.interceptor = interceptor;
	}
	
	public void disp(ISession session,IPacket packet) {
		TimeInterval timer = DateUtil.timer();
		try {
			boolean bool = (interceptor!=null && interceptor.handler(session,packet));
			if(!bool){
				Consumer<IPacket> consumer = module(session,packet);
				if(consumer != null){
					consumer.accept(packet);
				}
			}
		} catch (Exception e) {
			packet.getBody().clear();
			if (e instanceof AbstractArtifactException) {
				packet.setStatus(((AbstractArtifactException) e).getCode());
			}else {
				packet.setStatus(ArtifactErrorCode.UNKNOWN_ERROR);
				log.error(e);
			}
			session.sendPacket(packet);
		}  finally {
			// 记录执行时间
			log.debug("commandId : {} execute time : {}",packet.getCmd(), timer.interval());
		}
	}
	
	public Consumer<IPacket> module(ISession session,IPacket packet) {
		IModule module = modules.get(packet.getModuleId());
		ArtifactExceptionUtil.isTrue(ArtifactErrorCode.NOT_FOND_ACTION, module == null);
		return module.disp(session, packet);
	}

	@Override
	public boolean start() {
		try {
			modules = scanner.call();
			return true;
		} catch (Exception e) {
			log.error(e);
		}
		return false;
	}

	@Override
	public boolean stop() {
		return true;
	}
}
